fn main() {
    println!("=====================================");
    test01_match_literal_value();
    println!("=====================================");
    test02_named_variables();
    println!("=====================================");
    test03_mul_pattern();
    println!("=====================================");
    test04_match_range();
    println!("=====================================");
    test05_deconstruction();
    println!("=====================================");
    test06_deconstruct_enum();
    println!("=====================================");
    test07_nest();
    println!("=====================================");
    test08_complex_tuple();
    println!("=====================================");
    test09_match_ignore_one();
    println!("=====================================");
    test10_match_ignore_multi();
    println!("=====================================");
    test11_match_guard();
    println!("=====================================");
    test12_at_operator();
    println!("=====================================");
}

fn test01_match_literal_value() {
    let x = 1;
    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}
fn test02_named_variables() {
    let x = Some(5);
    let y = 10;
    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched,y = {y}"),
        _ => println!("Default case,x = {x:?}"),
    }
    println!("at the end: x = {x:?}, y = {y}");
}
fn test03_mul_pattern() {
    let x = 1;
    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}
fn test04_match_range() {
    let x = 5;

    match x {
        1..=5 => println!("one through five"),
        _ => println!("something else"),
    }

    let x = 'c';

    match x {
        'a'..='j' => println!("early ASCII letter"),
        'k'..='z' => println!("late ASCII letter"),
        _ => println!("something else"),
    }
}
struct Point {
    x: i32,
    y: i32,
}

//#[test]
fn test05_deconstruction() {
    let p = Point { x: 0, y: 7 };

    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);

    let Point { x, y } = p;
    assert_eq!(0, x);
    assert_eq!(7, y);

    let p = Point { x: 0, y: 0 };

    match p {
        Point { x, y: 0 } => println!("On the x axis at {x}"),
        Point { x: 0, y } => println!("On the y axis at {y}"),
        Point { x, y } => {
            println!("On neither axis: ({x}, {y})");
        }
    }
}
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn test06_deconstruct_enum() {
    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.");
        }
        Message::Move { x, y } => {
            println!("Move in the x direction {x} and in the y direction {y}");
        }
        Message::Write(text) => {
            println!("Text message: {text}");
        }
        Message::ChangeColor(r, g, b) => {
            println!("Change color to red {r}, green {g}, and blue {b}");
        }
    }
}
enum Color {
    Rgb(i32, i32, i32),
    Hsv(i32, i32, i32),
}

enum MessageWithColor {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(Color),
}

fn test07_nest() {
    let msg = MessageWithColor::ChangeColor(Color::Hsv(0, 160, 255));

    match msg {
        MessageWithColor::ChangeColor(Color::Rgb(r, g, b)) => {
            println!("Change color to red {r}, green {g}, and blue {b}");
        }
        MessageWithColor::ChangeColor(Color::Hsv(h, s, v)) => {
            println!("Change color to hue {h}, saturation {s}, value {v}");
        }
        _ => (),
    }
}

fn test08_complex_tuple() {
    let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}

fn foo(_: i32, y: i32) {
    println!("This code only uses the y parameter: {y}");
}
fn test09_match_ignore_one() {
    {
        foo(1, 2);
    }
    {
        let mut setting_value = Some(5);
        let new_setting_value = Some(10);

        match (setting_value, new_setting_value) {
            (Some(_), Some(_)) => {
                println!("Can't overwrite an existing customized value");
            }
            _ => {
                setting_value = new_setting_value;
            }
        }

        println!("setting is {setting_value:?}");
    }
    {
        let numbers = (2, 4, 8, 16, 32);

        match numbers {
            (first, _, third, _, fifth) => {
                println!("Some numbers: {first}, {third}, {fifth}");
            }
        }
    }
    {
        let _x = 5; //ignore warning
        let y = 10; //Rust warning
    }
    {
        let s = Some(String::from("Hello!"));
        //_s has owner
        if let Some(_s) = s {
            println!("found a string");
        }
        //println!("{s:?}");//error//s -> _s

        let s = Some(String::from("Hello!"));
        //_ don't has owner
        if let Some(_) = s {
            println!("found a string");
        }
        println!("{s:?}");
    }
}

struct Point3 {
    x: i32,
    y: i32,
    z: i32,
}
fn test10_match_ignore_multi() {
    {
        let origin = Point3 { x: 0, y: 0, z: 0 };

        match origin {
            Point3 { x, .. } => println!("x is {x}"),
        }
    }
    {
        let numbers = (2, 4, 8, 16, 32);

        match numbers {
            (first, .., last, _) => {
                println!("Some numbers: {first}, {last}");
            }
        }
    }
}
fn test11_match_guard() {
    {
        let num = Some(4);

        match num {
            Some(x) if x % 2 == 0 => println!("The number {x} is even"),
            Some(x) => println!("The number {x} is odd"),
            None => (),
        }
    }
    {
        let x = Some(5);
        let y = 10;

        match x {
            Some(50) => println!("Got 50"),
            Some(n) if n == y => println!("Matched, n = {n}"),
            _ => println!("Default case, x = {x:?}"),
        }

        println!("at the end: x = {x:?}, y = {y}");
    }
    {
        let x = 4;
        let y = false;

        match x {
            4 | 5 | 6 if y => println!("yes"), //(4 | 5 | 6) if y => ...
            _ => println!("no"),
        }
    }
}

fn test12_at_operator() {
    enum Message {
        Hello { id: i32 },
    }
    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id: id_variable @ 3..=7,
        } => println!("Found an id in range: {id_variable}"),
        Message::Hello { id: 10..=12 } => {
            println!("Found an id in another range")
        }
        Message::Hello { id } => println!("Found some other id: {id}"),
    }
}
